﻿using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

namespace ZL_Framework
{
    /// <summary>
    /// Log工具
    /// </summary>
    public class LogTool : MonoSingleton<LogTool>
    {
        public Text stuteText;
        public Text logText;
        private int LogMaxNum = 100;

        private string logStr;
        private bool isShowLog;

        public float updateInterval = 0.5f;
        private int totalFrame = 0;
        private float lastUpdateTime = 0f;
        private string fpsText = "", luaMemoryText = "", memoryText = "";

        private string initTime;

        public void Log(string message)
        {
            //message = "[ZL]  " + DateTime.Now + "  " + message;
            message = "[ZL]  " + message;
            Debug.Log(message);
        }

        public void LogError(string message)
        {
            //message = "[ZL Error!!]  " + DateTime.Now + "  " + message;
            message = "[ZL Error!!]  " + message;
            Debug.LogError(message);
        }

        private Queue<string> logQueue = new Queue<string>();
        private void LogShow(string str)
        {
#if DEV
            if (logQueue.Count >= LogMaxNum)
            {
                logQueue.Dequeue();
            }
            logQueue.Enqueue(str);
            SetStr();
#endif
        }

        private void SetStr()
        {
            logStr = "";
            foreach (var item in logQueue)
            {
                logStr += item + "\n";
            }
            logText.text = logStr;
        }

        private void StuteShow()
        {
            if (!isShowLog)
                return;
            totalFrame++;
            if (Time.realtimeSinceStartup - lastUpdateTime > updateInterval)
            {
                fpsText = "FPS: " + (totalFrame / (Time.realtimeSinceStartup - lastUpdateTime)).ToString("F2");
                if (LuaManager.Instance.Luaenv != null)
                {
                    luaMemoryText = "Lua Memory: " + LuaManager.Instance.Luaenv.Memroy.ToString() + "K";
                }
                //memoryText = "Total Memory: " + (Profiler.GetMonoUsedSizeLong() / 1024 / 1024f).ToString("F2") + "M";
                totalFrame = 0;
                lastUpdateTime = Time.realtimeSinceStartup;
                stuteText.text = fpsText + "\n" + luaMemoryText + "\n" + memoryText;
            }
        }

        /// <summary>
        /// 把log写到本地缓存
        /// </summary>
        /// <param name="log">log内容</param>
        /// <param name="type">log类型</param>
        private void WriteLogToLocal(string log, LogType type)
        {
            fs = new FileStream(newlogPath, FileMode.Append);
            sw = new StreamWriter(fs);
            if (sw != null)
            {
                sw.WriteLine(DateTime.Now + " " + type.ToString() + " " + log);
            }
            sw?.Close();
            fs?.Close();
        }

        /// <summary>
        /// 写入初始化信息
        /// </summary>
        private void WriteInitInfo()
        {
            fs = new FileStream(newlogPath, FileMode.Create);
            sw = new StreamWriter(fs);

            sw.WriteLine("StartupTime：" + DateTime.Now);
            sw.WriteLine("Identifier：" + Application.identifier);
            sw.WriteLine("Version：" + Application.version);
            sw.WriteLine("UnityVersion：" + Application.unityVersion);
            sw.WriteLine("DeviceModel：" + SystemInfo.deviceModel);
            sw.WriteLine("DeviceName：" + SystemInfo.deviceName);
            sw.WriteLine("DeviceType：" + SystemInfo.deviceType);
            sw.WriteLine("OS：" + SystemInfo.operatingSystem);
            sw.WriteLine("DeviceUniqueIdentifier：" + SystemInfo.deviceUniqueIdentifier);
            sw.WriteLine("MemorySize：" + SystemInfo.systemMemorySize);
            sw.WriteLine("GraphicsDeviceName：" + SystemInfo.graphicsDeviceName);
            sw.WriteLine("GraphicsDeviceType：" + SystemInfo.graphicsDeviceType);
            sw.WriteLine("GraphicsDeviceVendor：" + SystemInfo.graphicsDeviceVendor);
            sw.WriteLine("GraphicsDeviceVendorID：" + SystemInfo.graphicsDeviceVendorID);
            sw.WriteLine("GraphicsDeviceVersion：" + SystemInfo.graphicsDeviceVersion);
            sw.WriteLine("GraphicsMemorySize：" + SystemInfo.graphicsMemorySize);
            sw.WriteLine("GraphicsMultiThreaded：" + SystemInfo.graphicsMultiThreaded);
            sw.WriteLine("SupportedRenderTargetCount：" + SystemInfo.supportedRenderTargetCount);
            sw.WriteLine("MaxTextureSize：" + SystemInfo.maxTextureSize);
            sw.WriteLine("ProcessorType：" + SystemInfo.processorType);
            sw.WriteLine("ProcessorCount：" + SystemInfo.processorCount);
            sw.WriteLine("ProcessorFrequency：" + SystemInfo.processorFrequency);
            sw.WriteLine("");
            sw.WriteLine("-----------------------------------------------------------------------------------------");

            sw?.Close();
            fs?.Close();
        }

        /// <summary>
        /// 删除7天前的log文件
        /// </summary>
        /// <param name="path">log目录</param>
        private void DeleteOldLog(string path)
        {
            DirectoryInfo d = new DirectoryInfo(path);
            FileSystemInfo[] fsinfos = d.GetFileSystemInfos();
            foreach (FileSystemInfo item in fsinfos)
            {
                DateTime fileDate = item.CreationTime;
                if ((DateTime.Now - fileDate).TotalDays >= 7)
                {
                    File.Delete(item.FullName);
                }
            }
        }

        private void Update()
        {
#if DEV
            StuteShow();
#endif
            if (Input.GetKeyDown(KeyCode.L))
            {
                isShowLog = !isShowLog;
                logText.enabled = isShowLog;
                stuteText.enabled = isShowLog;
            }
        }

        protected override void Destroy()
        {
            sw?.Close();
            fs?.Close();
            logQueue?.Clear();
            logQueue = null;
            logStr = string.Empty;
            Application.logMessageReceived -= LogCallback;
        }

        FileStream fs;
        StreamWriter sw;
        string newlogPath;
        protected override void Init()
        {
            initTime = DateTime.Now.ToString("yyyyMMddHHmmss");
            string logPath = Path.Combine(Application.persistentDataPath, "log");
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }
            newlogPath = Path.Combine(logPath, "log_" + initTime + ".txt");

            WriteInitInfo();
            DeleteOldLog(logPath);

            logQueue?.Clear();
            isShowLog =
#if DEV
                true;
#else
                false;
#endif
            totalFrame = 0;
            lastUpdateTime = Time.realtimeSinceStartup;

            Application.logMessageReceived += LogCallback;
        }

        private void LogCallback(string condition, string stackTrace, LogType type)
        {
            string s = "";
            if (isShowLog)
            {
                switch (type)
                {
                    case LogType.Assert:
                    case LogType.Log:
                        s = "L:" + condition;
                        break;
                    case LogType.Warning:
                        s = "W:" + condition;
                        break;
                    case LogType.Error:
                    case LogType.Exception:
                        if (string.IsNullOrEmpty(stackTrace))
                        {
                            stackTrace = Environment.StackTrace;
                        }
                        s = "E:" + condition + "\n" + stackTrace;
                        break;
                    default:
                        break;
                }
                LogShow(s);
            }
            WriteLogToLocal(s, type);
        }
    }
}